package reflect

import (
	"fmt"
	"reflect"
)

func reflectType(x interface{}) {
	t := reflect.TypeOf(x)
	fmt.Printf("type:%v, kind: %v\n", t.String(), t.Kind())
}

func reflectValue(x interface{}) {
	v := reflect.ValueOf(x)
	k := v.Kind()
	if k == reflect.Ptr {
		v = v.Elem()
		k = v.Kind()
	}

	switch k {
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
		fmt.Println(v.Int())
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
		fmt.Println(v.Uint())
	case reflect.Float32, reflect.Float64:
		fmt.Println(v.Float())
	case reflect.String:
		fmt.Println(v.String())
	}
}

func TestType1() {
	var a *float32
	var b int
	var c rune

	reflectType(a)
	reflectType(b)
	reflectType(c)

	type person struct {
		name string
		age  int
	}

	type book struct {
		title string
	}

	var d = person{
		"a", 18,
	}
	var e = book{"aa"}

	var f = person{}

	reflectType(d)
	reflectType(e)
	reflectType(f)

	var a1 float32 = 3.14
	var b1 int64 = 100
	reflectValue(a1)
	reflectValue(b1)

	c1 := reflect.ValueOf(100)
	fmt.Printf("type:%T, value: %v\n", c1, c1)

	a2 := 1000
	//获取value为值拷贝，无法修改值
	v1 := reflect.ValueOf(a2)
	//通过指针修改值
	v2 := reflect.ValueOf(&a2)

	fmt.Println(v1.Kind(), v2.Kind())
	if v1.Kind() == reflect.Int {
		fmt.Println(v1.Int())
	}
	if v2.Elem().Kind() == reflect.Int {
		v2.Elem().SetInt(201)
	}

	fmt.Println(a2)

	fmt.Println(v1.IsValid(), v1.IsZero(), v1.CanAddr(), v1.CanInterface(), v1.CanSet())
}

type student struct {
	Name  string `json:"name"`
	Score int    `json:"score"`
}

func (s *student) Func1() {
	fmt.Println(1)
}

func (s *student) Func2() {
	fmt.Println(2)
}

func TestStructField() {
	stu1 := student{
		"aa", 18,
	}

	t := reflect.TypeOf(stu1)
	fmt.Println(t.Name(), t.Kind())

	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		fmt.Println(field.Name, field.Type, field.Index, field.PkgPath, field.Tag.Get("json"))
	}

	if scoreF, ok := t.FieldByName("Score"); ok {
		fmt.Println(scoreF.Name, scoreF.Type, scoreF.Index, scoreF.PkgPath, scoreF.Tag.Get("json"))
	}

	v := reflect.ValueOf(&stu1)
	for i := 0; i < t.NumField(); i++ {
		fieldv := v.Elem().Field(i)
		field := t.Field(i)

		if field.Name == "Name" {
			fieldv.SetString("aaa")
		}
		if field.Name == "Score" {
			fieldv.SetInt(1001)
		}
	}

	fmt.Println(stu1)

	v = reflect.ValueOf(&stu1)
	t = reflect.TypeOf(&stu1)

	fmt.Println(t.NumMethod())
	for i := 0; i < t.NumMethod(); i++ {
		method := t.Method(i)
		fmt.Println(method.Name, method.Type, method.Index, method.PkgPath)

		args := []reflect.Value{v}
		method.Func.Call(args)
	}
}
